package service.impl;

import domain.DomainObject;
import exceptions.GeneralServiceException;
import java.util.Collection;
import java.util.List;
import javax.persistence.EntityManager;
import service.IGenericService;

/**
 *
 * @author yuyok
 *
 */
public abstract class GenericServiceImpl<T extends DomainObject> implements IGenericService<T> {

    private Class<T> entityClass;

    public GenericServiceImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    //TODO: use or not ?
    /*
     * delete entity's collections before delete the entity
     */
//    protected abstract void beforeEntityDelete(T entity);

    @Override
    public void delEntityById(Long id) {

        if (id == null) {
            throw new IllegalArgumentException("GenericServiceImpl.IdIsNull");
        }

        EntityManager em = getEntityManager();

        em.remove(em.find(entityClass, id));
        // Getting entity by id
        T savedEntity = getEntityById(id);

        if (savedEntity != null) {
            // Deleting entity
            delEntity(savedEntity);
        }
    }

    @Override
    public void delEntity(T entity) {

        if (entity == null) {
            throw new IllegalArgumentException("GenericServiceImpl.ErrorEntityNull");
        }
        if (entity.getId() == null) {
            //log.warn("Trying to delete transient entity: " + entity); 
            return;
        }

        EntityManager em = getEntityManager();

        if (!em.contains(entity)) {
            T attachedEntity = em.merge(entity);
            em.remove(attachedEntity);
        } else {
            em.remove(entity);
        }
    }

    @Override
    public void delAllEntities(Collection<Long> ids) {

        if (ids == null) {
            throw new IllegalArgumentException("GenericServiceImpl.ErrorCollectionEntitiesNullForDelete");
        }

        if (!ids.isEmpty()) {

            for (Long id : ids) {
                T savedEntity = getEntityById(id);

                if (savedEntity != null) {
                    // Deleting entity
                    delEntity(savedEntity);
                } else {
                    // Doing nothing if entity is not found
                }
            }
        }
    }

    @Override
    public T getEntityById(Long id) {

        if (id == null) {
            throw new IllegalArgumentException("GenericServiceImpl.ErrorEntityIdNull");
        }

        try {
            T savedEntity = getEntityManager().find(entityClass, id);

            if ((savedEntity == null) || (savedEntity.getId() == null)) {
                return null;
            }

            return savedEntity;

        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public T save(T entity) throws GeneralServiceException {

        if (entity == null) {
            throw new IllegalArgumentException("Entity for saving cannot be null!");
        }

        T savedEntity = null;

        try {
            EntityManager em = getEntityManager();

            if (entity.getId() == null) {
                em.persist(entity);
                savedEntity = entity;
            } else {
                savedEntity = em.merge(entity);
            }

        } catch (Exception e) {
            if (entity.getId() == null) {
                throw new GeneralServiceException("GenericServiceImpl.ErrorFailedToAdd");
            } else {
                throw new IllegalArgumentException("already exists");
            }
        }

        return savedEntity;
    }

}
